package com.ct.boss.demo.interceptor;


import com.ct.boss.demo.annotation.PassToken;
import com.ct.boss.demo.annotation.UserLogin;
import com.ct.boss.demo.dao.SysUserMapper;
import com.ct.boss.demo.exception.BusinessException;
import com.ct.boss.demo.http.HttpStatus;
import com.ct.boss.demo.model.SysUser;
import com.ct.boss.demo.utils.TokenUtil;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.ExpiredJwtException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Method;

/**
 * @description 拦截请求 进行token验证
 * @author ChenTong
 * @date 2020/6/15 11:59
 */
@Slf4j
public class AuthenticationInterceptor implements HandlerInterceptor {

    // ?使用userservice
    @Autowired
    SysUserMapper userMapper;

    /**
     * @description 验证token,从请求头中获取token,从token中解析出用户名
     * 根据用户名查询数据库判断用户是否存在并将其用户信息存放到请求attribute中
     * 放行
     * @author ChenTong
     * @param httpServletRequest
     * @param httpServletResponse
     * @param object
     * @return boolean
     * @date 2020/6/16 12:00
     */
    @Override
    public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object object){

        //设置允许的ajax访问域名应用
        httpServletResponse.setHeader("Access-Control-Allow-Origin","*");
        httpServletResponse.setHeader("Access-Control-Allow-Methods","GET,PUT,POST,DELETE,HEAD");
        httpServletResponse.setHeader("Access_Control-Allow-Headers","Origin,X-Requested-With,content-Type,Accept,Authorization");
        httpServletResponse.setHeader("Access-Control-Max-Age","3600");

        //获取请求头token
        String token = "";
        String authorization = httpServletRequest.getHeader("Authorization");

        if(authorization!=null&&authorization.contains("Bearer ")){
            token += authorization.split(" ")[1];
        }else {
            token = authorization;
        }
       log.info("authorization:::::::"+authorization);

        //如果不是映射到方法直接通过
        if(!(object instanceof HandlerMethod)){
            return true;
        }
        HandlerMethod handlerMethod = (HandlerMethod) object;
        Method method = handlerMethod.getMethod();

        //检验是否含有passtoken注释，有则跳过验证
        if (isPass(method))
            //跳过验证
            return true;
        UserLogin userLoginToken = method.getAnnotation(UserLogin.class);
        //检查是否有需要用户权限的注释
        if (!(method.isAnnotationPresent(UserLogin.class)&&userLoginToken.required()))
            // 直接跳过
            return true;

        //执行验证
        if(token==null||token.equals("")){
            throw new BusinessException(HttpStatus.NO_TOKEN.getCode(), "无token");
        }else{
            //获取token中的用户信息
            Claims claims;
            //验证token
            try{
                claims = TokenUtil.parseJWT(token);
            }catch (ExpiredJwtException e){
                throw new BusinessException(HttpStatus.USER_NOT_EXIT.getCode(), "用户不存在");
            }
            //获取token中的用户名
            String username = claims.getId();
            SysUser user = userMapper.selectByUserName(username);
            if(user==null){//检验用户是否存在
                throw new BusinessException(HttpStatus.USER_NOT_EXIT.getCode(), "用户不存在");
            }
            //在请求中加入用户信息方便获取
            httpServletRequest.setAttribute("CurrentUser",user);
            httpServletRequest.setAttribute("CurrentUserID",user.getUserId());
        }

        return true;
    }
    /**
     * @description 判断是否可以通过验证
     * @author ChenTong
     * @param method :  
     * @return boolean
     * @date 2020/6/17 11:39
     */
    private boolean isPass(Method method){
        if(method.isAnnotationPresent(PassToken.class)){
            PassToken passToken = method.getAnnotation(PassToken.class);
            if(passToken.required()){
                return true;
            }
        }
        return false;
    }

    // 请求处理之后进行调用，但是在视图被渲染之前（Controller方法调用之后）
    @Override
    public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {
        // DO NOTHING
    }
    
    // 在整个请求结束之后被调用，也就是在DispatcherServlet 渲染了对应的视图之后执行（主要是用于进行资源清理工作）
    @Override
    public void afterCompletion(HttpServletRequest httpServletRequest,
                                HttpServletResponse httpServletResponse,
                                Object o, Exception e) throws Exception {
        // DO NOTHING
    }

}
